%{
#include<stdio.h>
#include<stdlib.h>

#ifndef _DATABASE_OPERATION_HEADER_
#define _DATABASE_OPERATION_HEADER_

#include "../include/operation.h"

#endif

#ifndef _AST_HEADER_
#define _AST+HEADER_
#include "../include/ast.h"
#endif

extern int yylex();
extern void executeSQL();
void yyerror(char * s);

%}

%union{
    double d;
    int number;
    char * m_string;
    int cp;
    // 这里不能使用typedef定义的，只能采用原始的结构体定义
    struct Data * m_data;
    struct CreateField * m_createField;
    struct Create * m_create;
    struct TableList * m_tableList;
    struct Condition * m_condition;
    struct SelectedField * m_selectedField;
    struct SelectedTable * m_selectedTable;
    struct Select * m_select;
    struct UpdatedField * m_updateField;
    struct Update * m_update;
    struct Delete * m_delete;
    struct InsertField * m_insertField;
    struct InsertItem * m_insertItem;
    struct Insert * m_insert;
}

%token <number> NUMBER
%token <m_string> CHARACTER
%token <m_string> ID
%token <m_data> DATA_INT DATA_DOUBLE DATA_STRING
%token INT CHAR DOUBLE
%token CREATE EXIT INSERT TABLES SELECT DELETE UPDATE SET USE FROM DROP DATABASES DATABASE INTO VALUES WHERE AND OR TABLE SHOW DESC DELIMETER HELP NUL NOT IS EOL
%token FOREIGN PRIMARY KEY REFERENCES UNIQUE AUTOINCREMENT AS
%token <cp> CP

%type <m_createField> createField createFields
%type <m_create> createTableSql
%type <m_selectedField> selectField selectFields
%type <m_condition> condition conditions
%type <m_selectedTable> selectTables
%type <m_select> selectTableSql
%type <m_updateField> updateField updateFields
%type <m_update> updateSql
%type <m_delete> deleteSql
%type <m_insertItem> insertItem insertItems
%type <m_insertField> insertFields
%type <m_insert> insertSql

%start sqls

%%

// If you don't take the recursing,the statuting stack will be wrong.
// When the error occure,the statuting stack will be clear.  
// So if you don't take the 'sqls' as '%start' other while take the sql as '%start', you will find that your sqls excute rightly or wrongly one by one.
// When the first sql excutes right,the statuting tree store one: element sql, but the next right sql could not be statute rightly.Because sql can not be statute to sql.

sqls:
| sqls sql

sql: HELP DELIMETER{ executeSQL(NULL,HELPSQL);} 
| CREATE DATABASE ID DELIMETER{ executeSQL($3,CREATEDATABASESQL); }
| SHOW DATABASES DELIMETER{executeSQL(NULL,SHOWDATABASESSQL);}
| SHOW TABLES DELIMETER {executeSQL(NULL,SHOWTABLESSQL);}
| DESC ID DELIMETER { executeSQL($2,DESCSQL);} 
| EXIT DELIMETER {executeSQL(NULL,EXITSQL);}
| DROP DATABASE ID DELIMETER {executeSQL($3,DROPDATABASESQL);}
| USE ID DELIMETER {executeSQL($2,USESQL);}
| DROP TABLE ID DELIMETER {executeSQL($3,DROPTABLESQL);}
| createTableSql {executeSQL($1,CREATESQL);}
| selectTableSql {executeSQL($1,SELECTSQL);}
| deleteSql {executeSQL($1,DELETESQL);}
| updateSql  {executeSQL($1,UPDATESQL);}
| insertSql {executeSQL($1,INSERTSQL);}


insertSql:
	INSERT INTO ID VALUES '(' insertItems ')' DELIMETER {
		struct Insert * ip = (struct Insert *) malloc(sizeof(struct Insert));
		ip->table = $3;
		ip->fields = NULL;
		ip->items = $6;
		$$ = ip;
	}
	| INSERT INTO ID '(' insertFields ')' VALUES '(' insertItems ')' DELIMETER {
		struct Insert * ip = (struct Insert *) malloc(sizeof(struct Insert));
		ip->table = $3;
		ip->fields = $5;
		ip->items = $9;
		$$ = ip;
	}

insertItems:
	insertItem { $$ = $1; }
	| insertItems ',' insertItem {
		struct InsertItem * tmp = $1;
		while(tmp ->next  != NULL){
			tmp = tmp->next;
		}
		tmp -> next = $3;
		$$ = $1;
	}

insertItem:
	DATA_INT	{
		printf("data_int\n");
		struct InsertItem * iip = (struct InsertItem *) malloc(sizeof(struct InsertItem));
		iip->value = $1;
		iip->next = NULL;
		$$ = iip;
	}
	| DATA_STRING {
	printf("data_string\n");
                     		struct InsertItem * iip = (struct InsertItem *) malloc(sizeof(struct InsertItem));
                     		iip->value = $1;
                     		iip->next = NULL;
                     		$$ = iip;
                     	}
	| DATA_DOUBLE
	{
	printf("data_double\n");
        		struct InsertItem * iip = (struct InsertItem *) malloc(sizeof(struct InsertItem));
        		iip->value = $1;
        		iip->next = NULL;
        		$$ = iip;
        	}

insertFields:
	ID {
		struct InsertField * ifp = (struct InsertField *) malloc(sizeof(struct InsertField));
		ifp->fieldName = $1;
		ifp->next = NULL;
		$$ = ifp;
	}
	| insertFields ',' ID{
		struct InsertField * ifp = (struct InsertField *) malloc(sizeof(struct InsertField));
		ifp->fieldName = $3;
		ifp->next = NULL;
		struct InsertField * tmp = $1;
		while(tmp->next != NULL){
			tmp = tmp->next;
		}
		tmp->next = ifp;
		$$ = $1;
	}



createTableSql:
    CREATE TABLE ID '(' createFields ')' DELIMETER {
    	struct Create * cp = (struct Create *)malloc(sizeof(struct Create));
	cp->name = $3;
	cp->fields = $5;
	$$ = cp;
	}
//    | CREATE TABLE ID'(' createFields ',' foreignKeys')' DELIMETER

createFields:
	createField {
		$$ = $1;
	}
	| createFields ',' createField {
		struct CreateField * tmp = $1;
		while(tmp->next != NULL){
			tmp = tmp->next;
		}
		tmp->next = $3;
		$$ = $1;
	}

//createFieldWithRestrain:
//    createField {printf("\nget field\n");}
//    | createField PRIMARY KEY AUTOINCREMENT
//    | createFieldWithRestrain NOT NUL
//    | createFieldWithRestrain UNIQUE


createField:
    ID CHAR '(' DATA_INT ')' {
    	struct CreateField * cfp = (struct CreateField *)malloc(sizeof(struct CreateField));
    	cfp->name = $1;
    	cfp->type = FIELD_STRING;
    	cfp->length = $4->value.i;
    	cfp->next = NULL;
    	$$ = cfp;
    }
   |ID INT {
   	struct CreateField * cfp = (struct CreateField *)malloc(sizeof(struct CreateField));
       	cfp->name = $1;
       	cfp->type = FIELD_INT;
       	cfp->next = NULL;
       	$$ = cfp;
   }
   |ID DOUBLE {
  	struct CreateField * cfp = (struct CreateField *)malloc(sizeof(struct CreateField));
       	cfp->name = $1;
       	cfp->type = FIELD_DOUBLE;
       	cfp->next = NULL;
       	$$ = cfp;
   }

//foreignKeys:
//    foreignKey| foreignKeys ',' foreignKey
//
//foreignKey:
//    FOREIGN KEY '(' ID ')' REFERENCES ID '(' ID ')'
//
selectTableSql:
    SELECT '*' FROM selectTables DELIMETER {
    	struct Select * sp = (struct Select *)malloc(sizeof(struct Select));
	sp->fp = NULL;
	sp->tp = $4;
	sp->cp = NULL;
	$$ = sp;
    }
    | SELECT selectFields FROM selectTables DELIMETER {
    	struct Select * sp = (struct Select *)malloc(sizeof(struct Select));
    	sp->fp = $2;
    	sp->tp = $4;
    	sp->cp = NULL;
    	$$ = sp;
    }
    | SELECT '*' FROM selectTables WHERE conditions DELIMETER {
    	struct Select * sp = (struct Select *)malloc(sizeof(struct Select));
	sp->fp = NULL;
	sp->tp = $4;
	sp->cp = $6;
	$$ = sp;
    }
    | SELECT selectFields FROM selectTables WHERE conditions DELIMETER {
    	struct Select * sp = (struct Select *)malloc(sizeof(struct Select));
	sp->fp = $2;
	sp->tp = $4;
	sp->cp = $6;
	$$ = sp;
    }

selectFields:
    selectField {
    	$$ = $1;
    }
    | selectFields ',' selectField {
    	struct SelectedField * sfp = $1;
    	while(sfp -> next != NULL){
    		sfp = sfp->next;
    	}
    	sfp->next = $3;
    	$$ = $1;
    }

selectField:
    ID {
	struct SelectedField * sfp = (struct SelectedField *)malloc(sizeof(struct SelectedField));
	sfp->field = $1;
	sfp->table = NULL;
	sfp->alias = NULL;
	sfp->next = NULL;
	$$ = sfp;
    }
    | ID'.'ID {
    	struct SelectedField * sfp = (struct SelectedField *)malloc(sizeof(struct SelectedField));
	sfp->field = $3;
	sfp->table = $1;
	sfp->alias = NULL;
	sfp->next = NULL;
	$$ = sfp;
    }
    | ID'.'ID ID {
    	struct SelectedField * sfp = (struct SelectedField *)malloc(sizeof(struct SelectedField));
	sfp->field = $3;
	sfp->table = $1;
	sfp->alias = $4;
	sfp->next = NULL;
	$$ = sfp;
    }
    | ID  ID {
    	struct SelectedField * sfp = (struct SelectedField *)malloc(sizeof(struct SelectedField));
    	sfp->field = $1;
    	sfp->table = NULL;
    	sfp->alias = $2;
    	sfp->next = NULL;
    	$$ = sfp;
    }

selectTables:
    ID {
    	struct SelectedTable * stp = (struct SelectedTable *)malloc(sizeof(struct SelectedTable));
     	stp->table = $1;
     	stp->next = NULL;
     	$$ = stp;
     }
    | selectTables ',' ID {
    	struct SelectedTable * sfp = (struct SelectedTable *)malloc(sizeof(struct SelectedTable));
	sfp->table = $3;
	sfp->next = NULL;
	struct SelectedTable * tmp = $1;
	while(tmp -> next != NULL){
		tmp = tmp->next;
	}
	tmp->next = sfp;

	$$ = $1;
    }

updateSql:
   UPDATE ID SET updateFields DELIMETER {
	struct Update * up = (struct Update *) malloc( sizeof( struct Update ) );
	up->table = $2;
	up->fp = $4;
	up->cp = NULL;
	$$ = up;
   }
   | UPDATE ID SET updateFields WHERE conditions DELIMETER {
   	struct Update * up = (struct Update *) malloc( sizeof( struct Update ) );
	up->table = $2;
	up->fp = $4;
	up->cp = $6;
	$$ = up;
   }

updateFields:
	updateField { $$ = $1; }
	| updateFields ',' updateField {
		struct UpdatedField * tmp = $1;
		while(tmp->next != NULL){
			tmp = tmp -> next;
		}
		tmp->next = $3;
		$$ = $1;
	}
updateField:
	ID '=' DATA_INT {
		struct UpdatedField * updf = (struct UpdatedField *)malloc(sizeof(struct UpdatedField));
		updf->name = $1;
		updf->value = $3;
		updf->next = NULL;
		$$ = updf;
	}
	| ID '=' DATA_DOUBLE {
		struct UpdatedField * updf = (struct UpdatedField *)malloc(sizeof(struct UpdatedField));
		updf->name = $1;
			updf->value = $3;
		updf->next = NULL;
		$$ = updf;
	}
 	| ID '=' DATA_STRING {
 		struct UpdatedField * updf = (struct UpdatedField *)malloc(sizeof(struct UpdatedField));
		updf->name = $1;
			updf->value = $3;
		updf->next = NULL;
		$$ = updf;
 	}

deleteSql:
	DELETE FROM ID DELIMETER {
		struct Delete * del = malloc(sizeof(struct Delete));
		del->table = $3;
		del->cp = NULL;
		$$ = del;
	}
	| DELETE FROM ID WHERE conditions DELIMETER {
		struct Delete * del = malloc(sizeof(struct Delete));
		del->table = $3;
		del->cp = $5;
		$$ = del;
	}

conditions: condition {
	$$ = $1;
}
| '(' conditions ')' {
	$$ = $2;
}
| conditions AND condition {
	struct Condition * con = malloc(sizeof(struct Condition));
	con->left = $1;
	con->right = $3;
	con->cp = AND_CMP;
	$$ = con;
}
| conditions OR condition {
	struct Condition * con = malloc(sizeof(struct Condition));
	con->left = $1;
	con->right = $3;
	con->cp = OR_CMP;
	$$ = con;
}

condition:
    ID CP DATA_INT{
    	    struct Condition * con = (struct Condition *)malloc(sizeof(struct Condition));
            struct Condition * left = (struct Condition *)malloc(sizeof(struct Condition));
            struct Condition * right = (struct Condition *)malloc(sizeof(struct Condition));
            con->left = left;
            con->right = right;
            con->cp = $2;

            left->cp = NO_CMP;
            left->left = NULL;
            left->right = NULL;

            left->type = FIELD_ID;
             left->value = (DataStructPoint) malloc(sizeof(DataStruct));
		left->value->type = FIELD_STRING;
		left->value->value.m_string = $1;
            left->table = NULL;

            right->cp = NO_CMP;
            right->left = NULL;
            right->right = NULL;
            right->type = FIELD_INT;
            right->value = $3;
            right->table = NULL;

            $$ = con;
    }
    | ID CP DATA_DOUBLE{
    	struct Condition * con = (struct Condition *)malloc(sizeof(struct Condition));
        struct Condition * left = (struct Condition *)malloc(sizeof(struct Condition));
        struct Condition * right = (struct Condition *)malloc(sizeof(struct Condition));
        con->left = left;
        con->right = right;
        con->cp = $2;

        left->cp = NO_CMP;
        left->left = NULL;
        left->right = NULL;

        left->type = FIELD_ID;
         left->value = (DataStructPoint) malloc(sizeof(DataStruct));
            left->value->type = FIELD_STRING;
            left->value->value.m_string = $1;
        left->table = NULL;

        right->cp = NO_CMP;
        right->left = NULL;
        right->right = NULL;
        right->type = FIELD_DOUBLE;
        right->value = $3;
        right->table = NULL;

        $$ = con;
    }
    | ID CP DATA_STRING {
    struct Condition * con = (struct Condition *)malloc(sizeof(struct Condition));
    struct Condition * left = (struct Condition *)malloc(sizeof(struct Condition));
    struct Condition * right = (struct Condition *)malloc(sizeof(struct Condition));
    con->left = left;
    con->right = right;
    con->cp = $2;

    left->cp = NO_CMP;
    left->left = NULL;
    left->right = NULL;

    left->type = FIELD_ID;
    left->value = (DataStructPoint) malloc(sizeof(DataStruct));
    left->value->type = FIELD_STRING;
    left->value->value.m_string = $1;
    left->table = NULL;

    right->cp = NO_CMP;
    right->left = NULL;
    right->right = NULL;
    right->type = FIELD_STRING;
    right->value = $3;
    right->table = NULL;

    $$ = con;
    }
    |ID '=' DATA_INT{
         	 struct Condition * con = (struct Condition *) malloc(sizeof(struct Condition));
                 struct Condition * left = (struct Condition *) malloc(sizeof(struct Condition));
                 struct Condition * right = (struct Condition *) malloc(sizeof(struct Condition));
                 con->left = left;
                 con->right = right;
                 con->cp = EQ;

                 left->cp = NO_CMP;
                 left->left = NULL;
                 left->right = NULL;

                 left->type = FIELD_ID;
                 left->value = (DataStructPoint) malloc(sizeof(DataStruct));
		    left->value->type = FIELD_STRING;
		    left->value->value.m_string = $1;
                 left->table = NULL;

                 right->cp = NO_CMP;
                 right->left = NULL;
                 right->right = NULL;
                 right->type = FIELD_INT;
                 right->value = $3;
                 right->table = NULL;

                 $$ = con;
         }
         | ID '=' DATA_DOUBLE{
         	struct Condition * con = (struct Condition *) malloc(sizeof(struct Condition));
             struct Condition * left = (struct Condition *) malloc(sizeof(struct Condition));
             struct Condition * right = (struct Condition *) malloc(sizeof(struct Condition));
             con->left = left;
             con->right = right;
             con->cp = EQ;

             left->cp = NO_CMP;
             left->left = NULL;
             left->right = NULL;

             left->type = FIELD_ID;
             left->value = (DataStructPoint) malloc(sizeof(DataStruct));
                left->value->type = FIELD_STRING;
                left->value->value.m_string = $1;
             left->table = NULL;

             right->cp = NO_CMP;
             right->left = NULL;
             right->right = NULL;
             right->type = FIELD_DOUBLE;
             right->value = $3;
             right->table = NULL;

             $$ = con;
         }
         | ID '=' DATA_STRING {
         struct Condition * con = (struct Condition *) malloc(sizeof(struct Condition));
         struct Condition * left = (struct Condition *) malloc(sizeof(struct Condition));
         struct Condition * right = (struct Condition *) malloc(sizeof(struct Condition));
         con->left = left;
         con->right = right;
         con->cp = EQ;

         left->cp = NO_CMP;
         left->left = NULL;
         left->right = NULL;

         left->type = FIELD_ID;
          left->value = (DataStructPoint) malloc(sizeof(DataStruct));
             left->value->type = FIELD_STRING;
             left->value->value.m_string = $1;
         left->table = NULL;

         right->cp = NO_CMP;
         right->left = NULL;
         right->right = NULL;
         right->type = FIELD_STRING;
         right->value = $3;
         right->table = NULL;

         $$ = con;
         }
%%

void yyerror(char * error){
    fprintf(stderr, "error: %s\n",error);
}